package com.songcan.common.utils;


import lombok.Data;


import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import com.songcan.common.utils.Hex;

@Data
public class SimpleHash {
    private static final int DEFAULT_ITERATIONS = 1;

    private  AlgorithmName algorithmName = AlgorithmName.SHA256;

    private byte[] bytes;

    private byte[] salt;

    private int iterations;

    private String hexEncoded = null;
    private int hashIterations=5000;

    public SimpleHash(AlgorithmName algorithmName) {
        this.algorithmName = algorithmName;
        this.iterations = DEFAULT_ITERATIONS;
    }

    public SimpleHash(AlgorithmName algorithmName, String source)  {
        this(algorithmName, source, null, DEFAULT_ITERATIONS);
    }

    public SimpleHash(AlgorithmName algorithmName, String source, String salt){
        this(algorithmName, source, salt, DEFAULT_ITERATIONS);
    }
    public SimpleHash(AlgorithmName algorithmName, String source, String salt, int hashIterations){
        this.algorithmName = algorithmName;
        this.iterations = Math.max(DEFAULT_ITERATIONS, hashIterations);
        try{
            this.salt = salt.getBytes("UTF-8");
        }catch (Exception e){
            e.printStackTrace();
        }
        hash(source, salt, hashIterations);
    }

    private void hash(String source, String salt, int hashIterations) {
        byte[] saltBytes = salt != null ? salt.getBytes() : null;
        byte[] hashedBytes = hash(source.getBytes(), saltBytes, hashIterations);
        setBytes(hashedBytes);
    }

    public AlgorithmName getAlgorithmName() {
        return this.algorithmName;
    }

    public int getIterations() {
        return this.iterations;
    }

    public void setIterations(int iterations) {
        this.iterations = Math.max(DEFAULT_ITERATIONS, iterations);
    }

    protected MessageDigest getDigest(AlgorithmName algorithmName) {
        try {
            return MessageDigest.getInstance(algorithmName.getValue());
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        return null;
    }

    protected byte[] hash(byte[] bytes, byte[] salt, int hashIterations) {
        MessageDigest digest = getDigest(getAlgorithmName());
        if (salt != null) {
            digest.reset();
            digest.update(salt);
        }
        byte[] hashed = digest.digest(bytes);
        int iterations = hashIterations - 1; //already hashed once above
        //iterate remaining number:
        for (int i = 0; i < iterations; i++) {
            digest.reset();
            hashed = digest.digest(hashed);
        }
        return hashed;
    }

    public boolean isEmpty() {
        return this.bytes == null || this.bytes.length == 0;
    }

    public String toHex() {
        if (this.hexEncoded == null) {
            this.hexEncoded = Hex.encodeToString(getBytes());
        }
        return this.hexEncoded;
    }

    public boolean equals(Object o) {
        if (o instanceof SimpleHash) {
            SimpleHash other = (SimpleHash) o;
            return MessageDigest.isEqual(getBytes(), other.getBytes());
        }
        return false;
    }

    /**
     * Simply returns toHex().hashCode();
     *
     * @return toHex().hashCode()
     */
    public int hashCode() {
        if (this.bytes == null || this.bytes.length == 0) {
            return 0;
        }
        return Arrays.hashCode(this.bytes);
    }

    public enum AlgorithmName{
        SHA1("SHA-1"),SHA256("SHA-256"),SHA384("SHA-384"),SHA512("SHA-512");

        private String value;

        AlgorithmName(String value){
            this.value = value;
        }
        public String getValue(){
            return value;
        }
    }


    public Boolean matchPassword(String source, String salt, String target) {
        SimpleHash simpleHash =new SimpleHash(AlgorithmName.SHA256, source, salt, hashIterations);
        return target.equals(simpleHash.toHex());
    }

    public static void main(String[] args) {

        String q = "ef2f0b1ee1d0167795ed39a701fe73f081b0e7c94d0dcf854bc1da000629864f";
        SimpleHash simpleHash =new SimpleHash(AlgorithmName.SHA256, "123456", "d4aa84ebe6e57acda962f10dbb65cdba", 10);
        System.out.println(simpleHash.toHex().equals(q));
    }
}
